local L = LibStub("AceLocale-3.0"):GetLocale("AzCastBarOptions")
if (select(2,UnitClass("player")) ~= "SHAMAN") then
	return;
end

local _G = getfenv(0);
local GetTime = GetTime;
local UnitAura = UnitAura;
local FormatTime = AzCastBar.FormatTime;

local b = AzCastBar.CreateBar("Button");
local timers = {};
local frames = {};
local unit = "player";

-- Extra Options
local extraOptions = {
	{
		[0] = L["Additional"],
		{ type = "Color", var = "colNormal", default = { 0.4, 0.6, 0.8, 1.0 }, label = L["Normal Color"] },
		{ type = "Color", var = "colGood", default = { 0.45, 0.82, 0.55, 1 }, label = L["Good Color"] },
		{ type = "Color", var = "colWarn", default = { 0.8, 0.8, 0.2, 1 }, label = L["Warning Color"] },
		{ type = "Color", var = "colFail", default = { 1.0, 0.5, 0.5, 1 }, label = L["Failed Color"] },
	},
};

-- Spell Names
local maelstrom = GetSpellInfo(53817);
local feralSpirit, _, feralSpiritIcon = GetSpellInfo(51533);
local lightShield = GetSpellInfo(324);
local waterShield = GetSpellInfo(52127);
local earthShield = GetSpellInfo(974);
local bloodlust = GetSpellInfo(UnitFactionGroup("player") == FACTION_ALLIANCE and 32182 or 2825);

-- Vars
local ICON_QUESTIONMARK = "Interface\\Icons\\INV_Misc_QuestionMark";
local lastMaelstromStack;
local feralSpiritStart = 0;
local wpnImbuePattern = "(.+) %d+ %(%d+ .+%)";
local enchantShort = {
	["Flametongue"] = "FT",
	["Windfury"] = "WF",
	["Earthliving"] = "EL",
	["Frostbrand"] = "FB",
	["Rockbiter"] = "RB",
};

--------------------------------------------------------------------------------------------------------
--                                                Code                                                --
--------------------------------------------------------------------------------------------------------

-- OnUpdate
local function OnUpdate(self,elapsed)
	local timer = self.timer;
	if (timer.duration) then
		self.timeLeft = max(0,timer.endTime - GetTime());
	end
	self.status:SetValue(timer.duration and self.timeLeft or 1);
	self.time:SetText(timer.duration and (FormatTime(self.timeLeft)..(b.cfg.showTotalTime and " / "..FormatTime(timer.duration) or "")) or "");
	-- Blink Maelstrom Timer on 5 Stacks
	if (timer.blink) then
		local change = (sin(GetTime() * 600) + 1) / 2 * b.cfg.alpha / 2;
		self:SetAlpha(b.cfg.alpha - change);
	end
end

-- OnClick
local function OnClick(self,button)
	local timer = self.timer;
	if (timer.enchant) then
		CancelItemTempEnchantment(1);
		CancelItemTempEnchantment(2);
	end
end

-- Configure Bar
local function ConfigureBar(bar,id)
	bar:EnableMouse(1);
	bar:RegisterForClicks("RightButtonUp");
	bar:SetScript("OnUpdate",OnUpdate);
	bar:SetScript("OnClick",OnClick);
	tinsert(b.bars,bar);
	AzCastBar.ApplyBarSettingsSpecific(b,id);
	return bar;
end

-- Update Timers
local function UpdateTimers()
	-- Loop Timers and update bars
	local bar;
	for index, table in ipairs(timers) do
		bar = b.bars[index] or ConfigureBar(AzCastBar.CreateBar("Button"),index);
		bar.timer = table;
		bar.status:SetMinMaxValues(0,table.duration or 1);
		if (table.color) then
			bar.status:SetStatusBarColor(unpack(table.color));
		else
			bar.status:SetStatusBarColor(unpack(b.cfg.colNormal));
		end
		bar.name:SetText(table.label..(table.count and table.count > 1 and " ("..table.count..")" or ""));
		bar.icon:SetTexture(table.icon);
		bar:SetAlpha(b.cfg.alpha);
		bar:Show();
	end
	-- Hide all other frames
	for i = #timers + 1, #b.bars do
		b.bars[i]:Hide();
	end
end

-- Scan Weapon for Temp Enchant
local function ScanWeaponTipEnchant(slotId)
	AzCastBarTip:ClearLines();
	AzCastBarTip:SetInventoryItem("player",slotId);
	local enchant;
	for i = 6, AzCastBarTip:NumLines() do
		enchant = _G["AzCastBarTipTextLeft"..i]:GetText():match(wpnImbuePattern);
		if (enchant) then
			return enchantShort[enchant] or "??";
		end
	end
	return "??";
end

-- Scan Player Buffs
local name, rank, icon, count, debuffType, duration, expirationTime;
local function ScanPlayerBuffs()
	wipe(timers);
	-- Weapon Enchants
	local hasMainHandEnchant, mainHandExpiration, _, hasOffHandEnchant, offHandExpiration = GetWeaponEnchantInfo();
	local offhand = select(9,GetItemInfo(GetInventoryItemLink("player",17) or "")); --OffhandHasWeapon()
	local icon = GetInventoryItemTexture(unit,16) or ICON_QUESTIONMARK;
	local endTime, mh, oh;
	if (not hasMainHandEnchant) and (not hasOffHandEnchant) then
		tinsert(timers,{ label = "No Weapon Imbue", icon = icon, color = b.cfg.colFail });
	elseif (hasMainHandEnchant) and (not offhand or offhand == "INVTYPE_SHIELD") then
		mh = ScanWeaponTipEnchant(16);
		endTime = (GetTime() + mainHandExpiration / 1000);
		tinsert(timers,{ label = "Weapon Imbue ("..mh..")", icon = icon, duration = 30 * 60, endTime = endTime, enchant = 1, color = b.cfg.colGood });
	else
		mh, oh = ScanWeaponTipEnchant(16), ScanWeaponTipEnchant(17);
		endTime = (GetTime() + min(mainHandExpiration or 0,offHandExpiration or 0) / 1000);
		tinsert(timers,{ label = "Weapon Imbue ("..mh.."/"..oh..")", icon = icon, duration = 30 * 60, endTime = endTime, enchant = 1, color = (hasMainHandEnchant and hasOffHandEnchant and b.cfg.colGood or b.cfg.colWarn) });
	end
	-- Shield
	name, rank, icon, count, debuffType, duration, expirationTime = UnitAura(unit,lightShield);
	if (not name) then
		name, rank, icon, count, debuffType, duration, expirationTime = UnitAura(unit,waterShield);
		if (not name) then
			name, rank, icon, count, debuffType, duration, expirationTime = UnitAura(unit,earthShield);
		end
	end
	if (name) then
		tinsert(timers,{ label = name, icon = icon, count = count, duration = duration, endTime = expirationTime, color = (count == 1 and b.cfg.colWarn or nil) });
	else
		tinsert(timers,{ label = "No Elemental Shield", icon = ICON_QUESTIONMARK, color = b.cfg.colFail });
	end
	-- Heroism/Bloodlust
	name, rank, icon, count, debuffType, duration, expirationTime = UnitAura(unit,bloodlust);
	if (name) then
		tinsert(timers,{ label = bloodlust, icon = icon, duration = duration, endTime = expirationTime });
	end
	-- Maelstrom
	name, rank, icon, count, debuffType, duration, expirationTime = UnitAura(unit,maelstrom);
	if (name) then
		if (lastMaelstromStack ~= 5) and (count == 5) then
			PlaySoundFile("Sound\\Creature\\Murmur\\MurmurWoundA.wav");
		end
		tinsert(timers,{ label = name, icon = icon, count = count, duration = duration, endTime = expirationTime, blink = (count == 5), color = (count == 5 and b.cfg.colGood or nil) });
		lastMaelstromStack = count;
	end
	-- Spirit Wolves
	if (GetTime() - feralSpiritStart <= 45) then
		tinsert(timers,{ label = "Spirit Wolves", icon = feralSpiritIcon, duration = 45, endTime = (feralSpiritStart + 45) });
	end
	-- Update
	UpdateTimers();
end

--------------------------------------------------------------------------------------------------------
--                                           Event Handling                                           --
--------------------------------------------------------------------------------------------------------

local function OnEvent(self,event,p1,p2,...)
	-- Ability Cast
	if (event == "UNIT_SPELLCAST_SUCCEEDED") then
		if (p1 == "player") and (p2 == feralSpirit) then
			feralSpiritStart = GetTime();
			ScanPlayerBuffs();
		end
	-- Aura Change
	elseif (event ~= "UNIT_AURA" or p1 == unit) then
		ScanPlayerBuffs();
	end
end

-- Config Change
function b:OnConfigChanged(cfg,barId)
	if (barId ~= 1) then
		return;
	elseif (cfg.enabled) then
		self:RegisterEvent("UNIT_AURA");
		self:RegisterEvent("UNIT_INVENTORY_CHANGED"); -- For temp enchants
		self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED");
		ScanPlayerBuffs();
	else
		self:UnregisterAllEvents();
		wipe(timers);
		UpdateTimers();
	end
end

--------------------------------------------------------------------------------------------------------
--                                        Init AzCastBar Entry                                        --
--------------------------------------------------------------------------------------------------------

b.token = L["Shaman"];
b.options = extraOptions;
b.bars = {};
b:ClearAllPoints();
b:SetPoint("CENTER");
b:SetScript("OnEvent",OnEvent);
tinsert(AzCastBar.frames,b);
ConfigureBar(b,1);